package com.zebra.gateway.processor;

import com.zebra.common.OfflineType;
import com.zebra.gateway.protocol.GatewayCommand;
import com.zebra.gateway.session.LoginSessionManager;
import com.zebra.gateway.session.Session;
import com.zebra.gateway.session.SessionManager;
import com.zebra.remoting.config.BasisCommandCode;
import com.zebra.remoting.config.StateCode;
import com.zebra.remoting.connection.Connection;
import com.zebra.remoting.protocol.ProcessorType;
import com.zebra.remoting.util.RemotingUtil;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;

import java.util.concurrent.Executor;


public class ClientHandlerProcessor implements GatewayProcessor  {

    private static final InternalLogger logger = InternalLoggerFactory.getInstance(ClientHandlerProcessor.class);

    @Override
    public void process(ChannelHandlerContext ctx, GatewayCommand msg, Executor defaultExecutor) throws Exception {
            try {
                doProcess(ctx, msg);
            } catch (Exception e) {
                GatewayProcessorUtil.release(msg);
                logger.error("TMS Response Handler Exception; {} {} {}", e.getMessage(), msg.toString(), RemotingUtil.channelToString(ctx.channel()));
            }
    }


    public void doProcess(ChannelHandlerContext ctx, GatewayCommand msg) throws Exception {
        ProcessorType processorType = msg.getProcessorType();
        switch (processorType){
            case GM:      {doGM(ctx, msg); break;}
            case PUSH:    {doPUSH(ctx, msg); break;}

            case L_LOGIN: {doL_LOGIN(ctx, msg); break;}
            case L_RECON: {doL_RECON(ctx, msg); break;}
            case L_EXIT:  {doL_EXIT(ctx, msg);  break;}

            case G_LOGIN: {doG_LOGIN(ctx, msg); break;}
            case G_RECON: {doG_RECON(ctx, msg); break;}
            case G_EXIT:  {doG_EXIT(ctx, msg); break;}
            default: {
                doGM(ctx, msg);
            }
        }
    }

    //MewSession web 生成之后需要添加一个过期时间； 如果10分钟没有登录则Session 失效;
    private void doL_LOGIN(ChannelHandlerContext ctx, GatewayCommand msg)throws Exception{
        logger.warn("TMS L_LOGIN Response {}",   msg.toString());
        doLobbyLogin(ctx, msg);
    }

    //重连如果已经有用户在线则需要提示该用户在线; 不能重连
    private void doL_RECON(ChannelHandlerContext ctx, GatewayCommand msg)throws Exception{
        logger.warn("TMS L_RECON Response  {}",   msg.toString());
        doLobbyLogin(ctx, msg);
    }

    private void doLobbyLogin(ChannelHandlerContext ctx, GatewayCommand msg)throws Exception{
        Session session = LoginSessionManager.LOGINSESSION.removeSession(msg.getUserId());
        if (StateCode.Success.code() == msg.getState()){
            Connection lobbyConnection = Connection.getByChannel(ctx.channel());
            session.setToken(msg.getToken());
            session.setGameId(0);
            session.setTempGid(0);
            session.setLobbyConn(lobbyConnection);
            session.setWeakClose(false);
            SessionManager.getInstance().putSession(session);
            session.getChannel().writeAndFlush(msg);
        }else {
            session.getChannel().writeAndFlush(msg);
        }
    }


    private void doL_EXIT(ChannelHandlerContext ctx, GatewayCommand msg)throws Exception{
        logger.warn("TMS L_EXIT Response  {}",   msg.toString());
        Session session = getSessionByUid(msg.getUserId());
        if (StateCode.Success.code() != msg.getState()){
            session.getChannel().writeAndFlush(msg);
            checkLoginOut(msg.getState(), session);  // 校验是否 有 登录失效
            return;
        }
        session.getChannel().writeAndFlush(msg);
        SessionManager.getInstance().removeBySession(session);
    }


    //进入子游戏
    private void doG_LOGIN(ChannelHandlerContext ctx, GatewayCommand msg)throws Exception{
        logger.warn("TMS G_LOGIN Response {}",   msg.toString());
        Session session = getSessionByUid(msg.getUserId());
        if (StateCode.Success.code() != msg.getState()){
            session.getChannel().writeAndFlush(msg);
            session.setTempGid(0);
            checkLoginOut(msg.getState(), session); // 校验是否 有 登录失效
            return;
        }
        Connection connection = Connection.getByChannel(ctx.channel());
        session.setGameConn(connection);
        session.setGameId(session.getTempGid());
        session.setToken(msg.getToken());
        session.setTempGid(0);
        session.setWeakClose(false);
        session.getChannel().writeAndFlush(msg);
    }

    // 游戏重连
    private void doG_RECON(ChannelHandlerContext ctx, GatewayCommand msg)throws Exception{
        logger.warn("TMS G_RECON Response  {}",   msg.toString());
        Session session = LoginSessionManager.LOGINSESSION.removeSession(msg.getUserId());
        if (StateCode.Success.code() != msg.getState()){
            session.getChannel().writeAndFlush(msg);
            session.setTempGid(0);
            return;
        }

        Connection connection = Connection.getByChannel(ctx.channel());
        session.setGameConn(connection);
        session.setToken(msg.getToken());
        session.setTempGid(0);
        session.setWeakClose(false);
        SessionManager.getInstance().putSession(session);

        session.getChannel().writeAndFlush(msg);

    }

    //退出 游戏 返回大厅
    private void doG_EXIT(ChannelHandlerContext ctx, GatewayCommand msg)throws Exception{
        logger.warn("TMS G_EXIT Response {}",   msg.toString());
        Session session = getSessionByUid(msg.getUserId());
        if (StateCode.Success.code() == msg.getState()){
            session.setGameId(0);
            session.setGameConn(null);
            session.getChannel().writeAndFlush(msg);
            session.setTempExit(false);
        }else {
            session.setTempExit(false);
            session.getChannel().writeAndFlush(msg);
            checkLoginOut(msg.getState(), session);
        }
    }


    private void doGM(ChannelHandlerContext ctx, GatewayCommand msg)throws Exception{
        if (logger.isInfoEnabled()){
            logger.info("TMS GM Response  {}",   msg.toString());
        }
        Session session = getSessionByUid(msg.getUserId());
        session.getChannel().writeAndFlush(msg);
        checkLoginOut(msg.getState(), session); // 校验是否 有 登录失效
    }

    private void doPUSH(ChannelHandlerContext ctx, GatewayCommand msg)throws Exception{
        if (logger.isInfoEnabled()){
            logger.info("TMS PUSH Response  {}",   msg.toString());
        }
//        Session session = SessionManager.getInstance().getSession(msg.getUserId());
        Session session = getSessionByUid(msg.getUserId());
        if (session.getToken() == msg.getToken()){
            if (BasisCommandCode.EXPIRED.cmd() == msg.getCmd() || BasisCommandCode.OVERHAULED.cmd() == msg.getCmd()){
                session.setGameId(0);
                session.setGameConn(null);
            }
            msg.setToken(0L);
            session.getChannel().writeAndFlush(msg);
        }else {
            GatewayProcessorUtil.release(msg);
            logger.error("TMS PUSH MSG: stk {}, {}", null == session ? "session is null" : session.getToken(), msg.toString());
            GatewayProcessorUtil.sendTmsInactiveChannel(session, OfflineType.Push);
//            if (session != null){
//                GatewayProcessorUtil.sendTmsInactiveChannel(session, OfflineType.Push);
//            }
            //TODO session 为空也需要处理； 目前不处理 因为要分 子游戏 还是 大厅的推送消息 [可以通过ctx 返回消息，这样就不需要份大厅还是子游戏]
        }
    }


    private Session getSessionByUid(long userId)throws Exception{
        Session session = SessionManager.getInstance().getSession(userId);
        if (null != session){
            return session;
        }

        throw new  Exception("Session is null uid : "+userId);
    }

    private void checkLoginOut(int stateCode, Session session){
        if (StateCode.LoginUn.code() == stateCode){
            logger.warn("TMS LoginUn {}", null == session ? "session is null" : session.toString());
            SessionManager.getInstance().removeBySession(session);  // 移除 session
        }
    }


}
